#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/spinlock.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/usb.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/hid.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

extern unsigned char red[8230];
extern unsigned char blue[8267];
extern unsigned char green[8265];

struct vir_v4l2_device {
	unsigned long flags;

	struct device *dev;
	struct usb_device *udev;
	struct video_device vdev;
	struct v4l2_device v4l2_dev;

	/* videobuf2 queue and queued buffers list */
	struct vb2_queue vb_queue;
	struct list_head queued_bufs;
	spinlock_t queued_bufs_lock; /* Protects queued_bufs */
	unsigned sequence;	     /* Buffer sequence counter */
	unsigned int vb_full;        /* vb is full and packets dropped */

	/* Note if taking both locks v4l2_lock must always be locked first! */
	struct mutex v4l2_lock;      /* Protects everything else */
	struct mutex vb_queue_lock;  /* Protects vb_queue and capt_file */

	int            buf_num;
	unsigned long  buf_size;

	/* USB control message buffer */
	#define BUF_SIZE 128
	u8 buf[BUF_SIZE];

	/* Current configuration */
	unsigned int f_adc;
	unsigned int f_rf;
	u32 pixelformat;
	u32 buffersize;

	/* Controls */
	struct v4l2_ctrl_handler hdl;
	struct v4l2_ctrl *lna_gain_auto;
	struct v4l2_ctrl *lna_gain;
	struct v4l2_ctrl *mixer_gain_auto;
	struct v4l2_ctrl *mixer_gain;
	struct v4l2_ctrl *if_gain;

	/* Sample rate calc */
	unsigned long jiffies_next;
	unsigned int sample;
	unsigned int sample_measured;

    // 按键中断模拟,模拟产生数据
    int irq;
};

/* intermediate buffers with raw data from the USB device */
struct vir_v4l2_device_frame_buf {
	/* common v4l buffer stuff -- must be first */
	struct vb2_v4l2_buffer vb;
	struct list_head list;
};

/* Videobuf2 operations */
static int vir_v4l2_device_queue_setup(struct vb2_queue *vq,
		unsigned int *nbuffers,
		unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[])
{
	struct vir_v4l2_device *s = vb2_get_drv_priv(vq);

    // 至少需要8个buffer, 每个buffer只有1个plane

	/* Need at least 8 buffers */
	if (vq->num_buffers + *nbuffers < 8)
		*nbuffers = 8 - vq->num_buffers;
	*nplanes = 1;
    // 页的大小
	sizes[0] = PAGE_ALIGN(800 * 600 * 2);

	dev_err(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
	return 0;
}

 static void vir_v4l2_device_buf_queue(struct vb2_buffer *vb)
{
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	struct vir_v4l2_device *s = vb2_get_drv_priv(vb->vb2_queue);
	struct vir_v4l2_device_frame_buf *buf =
			container_of(vbuf, struct vir_v4l2_device_frame_buf, vb);
	unsigned long flags;

	spin_lock_irqsave(&s->queued_bufs_lock, flags);
    // 把buf告诉硬件,放入硬件的空闲队列中
	list_add_tail(&buf->list, &s->queued_bufs);
	spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
}

static int vir_v4l2_device_start_streaming(struct vb2_queue *vq, unsigned int count)
{
	struct vir_v4l2_device *s = vb2_get_drv_priv(vq);
	int ret = 0;

    // 启动传输
	mutex_lock(&s->v4l2_lock);

    // 通过中断方式触发接收数据传输,通过USB/MIPI获取数据
    // 用按键模拟触发中断,使能中断
    enable_irq(s->irq);
    
	mutex_unlock(&s->v4l2_lock);

	return ret;
}

/* Must be called with vb_queue_lock hold */
static void vir_v4l2_device_cleanup_queued_bufs(struct vir_v4l2_device *s)
{
	unsigned long flags = 0;

	spin_lock_irqsave(&s->queued_bufs_lock, flags);
	while (!list_empty(&s->queued_bufs)) {
		struct vir_v4l2_device_frame_buf *buf;
        // 删除空闲BUF中的数据,设置全部完成
		buf = list_entry(s->queued_bufs.next,
				struct vir_v4l2_device_frame_buf, list);
		list_del(&buf->list);
		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
	}
	spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
}


static void vir_v4l2_device_stop_streaming(struct vb2_queue *vq)
{
	struct vir_v4l2_device *s = vb2_get_drv_priv(vq);

    // 停止硬件传输

	mutex_lock(&s->v4l2_lock);
    // 关闭中断触发
    disable_irq_nosync(s->irq);
    // 清除BUF,设置BUF全部完成
    vir_v4l2_device_cleanup_queued_bufs(s);

	mutex_unlock(&s->v4l2_lock);
}

static const struct vb2_ops vir_v4l2_device_vb2_ops = {
    // 申请buffer空间
	.queue_setup            = vir_v4l2_device_queue_setup,
	.buf_queue              = vir_v4l2_device_buf_queue,
	.start_streaming        = vir_v4l2_device_start_streaming,
	.stop_streaming         = vir_v4l2_device_stop_streaming,
	.wait_prepare           = vb2_ops_wait_prepare,
	.wait_finish            = vb2_ops_wait_finish,
};

static int vir_v4l2_device_querycap(struct file *file, void *fh,
		struct v4l2_capability *cap)
{
	struct vir_v4l2_device *s = video_drvdata(file);

	strlcpy(cap->driver, "jz_vir_device", sizeof(cap->driver));
	strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
			V4L2_CAP_READWRITE;
	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;

	return 0;
}

/* stream formats */
struct vir_v4l2_format {
	char	*name;
	u32	pixelformat;
	u32	buffersize;
};

#define VIR_V4L2_DEVICE_BULK_BUFFER_SIZE         (128 * 512)

/* format descriptions for capture and preview */
static struct vir_v4l2_format vir_v4l2_device_formats[] = {
	{
		.name		= "Motion-JPEG",
		.pixelformat	= V4L2_PIX_FMT_MJPEG,
		.buffersize	= VIR_V4L2_DEVICE_BULK_BUFFER_SIZE,
	},
};

static const unsigned int NUM_FORMATS = ARRAY_SIZE(vir_v4l2_device_formats);

static int vir_v4l2_device_enum_fmt_cap(struct file *file, void *priv,
		struct v4l2_fmtdesc *f)
{
	if (f->index >= NUM_FORMATS)
		return -EINVAL;

    // 提供视频格式
	strlcpy(f->description, vir_v4l2_device_formats[f->index].name, sizeof(f->description));
	f->pixelformat = vir_v4l2_device_formats[f->index].pixelformat;

	return 0;
}

static int vir_v4l2_device_g_fmt_cap(struct file *file, void *priv,
		struct v4l2_format *f)
{
	// struct vir_v4l2_device *s = video_drvdata(file);
    
	f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
    f->fmt.pix.width = 800;
    f->fmt.pix.height = 600;
    f->fmt.pix.field = V4L2_FIELD_NONE;
    f->fmt.pix.bytesperline = 0;

	return 0;
}
        
static struct v4l2_frmsize_discrete vir_v4l2_framesizes_formats[] = {
	{
        .width = 800,
        .height = 600,
	},
};

static int vir_v4l2_device_enum_framesizes(struct file *file, void *fh,
				   struct v4l2_frmsizeenum *fsize)
{
    // V4L2_FRMSIZE_TYPE_DISCRETE 表示帧尺寸是离散的，即预定义了一组特定的宽度和高度选项供选择。
    // 相机或设备只能以这些预定义的尺寸之一生成图像帧。
    
    // V4L2_FRMSIZE_TYPE_CONTINUOUS 表示帧尺寸是连续的，允许使用范围内的任何宽度和高度值。
    // 相机或设备可以以任意宽度和高度生成图像帧，在给定范围内可以灵活调整帧的尺寸
    
    if (fsize->index >= ARRAY_SIZE(vir_v4l2_framesizes_formats))
        return -EINVAL;
    fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
    fsize->discrete.width = vir_v4l2_framesizes_formats[fsize->index].width;
    fsize->discrete.height = vir_v4l2_framesizes_formats[fsize->index].height;

    return 0;
}

static int vir_v4l2_device_s_fmt_cap(struct file *file, void *priv,
		struct v4l2_format *f)
{
	struct vir_v4l2_device *s = video_drvdata(file);
	struct vb2_queue *q = &s->vb_queue;
    
	if (vb2_is_busy(q))
		return -EBUSY;

    /* 分辨用户传入的参数是否可用
     * 如果不可用, 给APP提供最接近的、硬件支持的参数
    */

    if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
        return -EINVAL;

    f->fmt.pix.width = 800;
    f->fmt.pix.height = 600;

	return 0;
}

static const struct v4l2_ioctl_ops virtual_ioctl_ops = {
    // 提供查询能力
	.vidioc_querycap          = vir_v4l2_device_querycap,
	// 提供视频格式
	.vidioc_enum_fmt_vid_cap  = vir_v4l2_device_enum_fmt_cap,
	// 提供视频帧大小
	.vidioc_enum_framesizes   = vir_v4l2_device_enum_framesizes,
	// 提供获取当前视频格式
	.vidioc_g_fmt_vid_cap     = vir_v4l2_device_g_fmt_cap,
	// 提供设置视频格式
	.vidioc_s_fmt_vid_cap     = vir_v4l2_device_s_fmt_cap,

	.vidioc_reqbufs           = vb2_ioctl_reqbufs,
	.vidioc_create_bufs       = vb2_ioctl_create_bufs,
	.vidioc_prepare_buf       = vb2_ioctl_prepare_buf,
	.vidioc_querybuf          = vb2_ioctl_querybuf,
	.vidioc_qbuf              = vb2_ioctl_qbuf,
	.vidioc_dqbuf             = vb2_ioctl_dqbuf,

	.vidioc_streamon          = vb2_ioctl_streamon,
	.vidioc_streamoff         = vb2_ioctl_streamoff,

	.vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
	.vidioc_log_status        = v4l2_ctrl_log_status,
};

static const struct v4l2_file_operations virtual_fops = {
	.owner                    = THIS_MODULE,
	.open                     = v4l2_fh_open,
	.release                  = vb2_fop_release,
	.read                     = vb2_fop_read,
	.poll                     = vb2_fop_poll,
	.mmap                     = vb2_fop_mmap,
	.unlocked_ioctl           = video_ioctl2,
};

static const struct video_device vir_v4l2_device_template = {
	.name                     = "Virtual V4L2 Device",
	.release                  = video_device_release_empty,
	.fops                     = &virtual_fops,
	.ioctl_ops                = &virtual_ioctl_ops,
};

static void vir_v4l2_device_video_release(struct v4l2_device *v)
{
	struct vir_v4l2_device *s = container_of(v, struct vir_v4l2_device, v4l2_dev);

	v4l2_device_unregister(&s->v4l2_dev);
}

/* Private functions */
static struct vir_v4l2_device_frame_buf *vir_v4l2_device_get_next_fill_buf(struct vir_v4l2_device *s)
{
	unsigned long flags;
	struct vir_v4l2_device_frame_buf *buf = NULL;

	spin_lock_irqsave(&s->queued_bufs_lock, flags);
	if (list_empty(&s->queued_bufs))
		goto leave;

	buf = list_entry(s->queued_bufs.next,
			struct vir_v4l2_device_frame_buf, list);
	list_del(&buf->list);
leave:
	spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
	return buf;
}

static irqreturn_t vir_v4l2_device_streaming_handle(int irq, void *dev_id)
{
    struct vir_v4l2_device *s = (struct vir_v4l2_device *)dev_id;
    // 模拟数据的数据控制
    static unsigned int data_cnt = 0;
    void *ptr = NULL;
    struct vir_v4l2_device_frame_buf *fbuf = NULL;

    dev_err(NULL, "vir_v4l2_device_streaming_handle running\n");

    // 从硬件上读到数据(使用red/green/blue数组来模拟)

    // 往空闲链表buf中存放数据
    /* get free framebuffer */
    // 获取第1个空闲的BUF
    fbuf = vir_v4l2_device_get_next_fill_buf(s);
    if (unlikely(fbuf == NULL)) {
			s->vb_full++;
            dev_err(NULL, "videobuf is full, %d packets dropped\n", s->vb_full);
            return IRQ_NONE;
	}

    // fill framebuffer
    // 把数据填充写入buffer
    // 获取vb2_buf地址
    ptr = vb2_plane_vaddr(&fbuf->vb.vb2_buf, 0);
    if (data_cnt == 0) {
        // 复制数据到vb2_buf
        memcpy(ptr, red, sizeof(red));
        // 设置实际传输到vb2_buf的数据长度
        vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, sizeof(red));
    } else if (data_cnt == 1) {
        // 复制数据到vb2_buf
        memcpy(ptr, green, sizeof(green));
        // 设置实际传输到vb2_buf的数据长度
        vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, sizeof(green));
    } else {
        // 复制数据到vb2_buf
        memcpy(ptr, blue, sizeof(blue));
        // 设置实际传输到vb2_buf的数据长度
        vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, sizeof(blue));
    }

    fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
	fbuf->vb.sequence = s->sequence++;

    // 把数据buf移动到完成链表
    vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);

    data_cnt++;
    if (data_cnt == 3) {
        data_cnt = 0;
    }
    
    return IRQ_HANDLED;
}

static int vir_v4l2_dev_probe(struct platform_device *pdev)
{
    /* 分配v4l2设备空间 */
    struct vir_v4l2_device *s = NULL;
    struct device_node *np = pdev->dev.of_node;
    int ret = 0;

    s = devm_kzalloc(&pdev->dev, sizeof(struct vir_v4l2_device), GFP_KERNEL);
    if (s == NULL) {
		dev_err(&pdev->dev, "Could not allocate memory for state\n");
		return -ENOMEM;
	}

    /* 初始化V4l2设备锁 */
    // 互斥锁保护访问 V4L2 (Video4Linux) 相关的代码和数据结构
    mutex_init(&s->v4l2_lock);
    // 互斥锁用于保护访问视频缓冲区队列相关的代码和数据结构
	mutex_init(&s->vb_queue_lock);
    // 自旋锁保护访问已排队的视频缓冲区列表。自旋锁,它在等待锁时会一直忙等待,而不是睡眠
	spin_lock_init(&s->queued_bufs_lock);
    // 双向链表用于存储已排队的视频缓冲区
	INIT_LIST_HEAD(&s->queued_bufs);

    // 存储dev
    s->dev = &pdev->dev;

    /* Init videobuf2 queue structure */
    // 初始化videobuf2结构
    s->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
    // 存储私有数据
    s->vb_queue.drv_priv = s;
    s->vb_queue.buf_struct_size = sizeof(struct vir_v4l2_device_frame_buf);
    s->vb_queue.ops = &vir_v4l2_device_vb2_ops;
    s->vb_queue.mem_ops = &vb2_vmalloc_memops;
    s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
    // 初始vb_queue
    ret = vb2_queue_init(&s->vb_queue);
    if (ret) {
        dev_err(s->dev, "Could not initialize vb2 queue\n");
        goto err_free_mem;
    }

    /* Init video_device structure */
    // 初始化video_device模板
    s->vdev = vir_v4l2_device_template;
    s->vdev.queue = &s->vb_queue;
    s->vdev.queue->lock = &s->vb_queue_lock;
    video_set_drvdata(&s->vdev, s);

    /* Register the v4l2_device structure(辅助作用) */
    s->v4l2_dev.release = vir_v4l2_device_video_release;
    ret = v4l2_device_register(&pdev->dev, &s->v4l2_dev);
	if (ret) {
		dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
		goto err_free_mem;
	}

    // platform存储数据
    platform_set_drvdata(pdev, s);

    // 设置video device
    s->vdev.v4l2_dev = &s->v4l2_dev;
	s->vdev.lock = &s->v4l2_lock;

    // 注册video device
    ret = video_register_device(&s->vdev, VFL_TYPE_GRABBER, -1);
	if (ret) {
		dev_err(s->dev, "Failed to register as video device (%d)\n",
				ret);
		goto err_free_controls;
	}

    // 模拟通过按键中断产生数据
    //尝试从gpio转irq尝试
    s->irq = gpio_to_irq(of_get_named_gpio(np, "eint-pins", 0));
    ret = devm_request_irq(&pdev->dev, s->irq, vir_v4l2_device_streaming_handle, IRQF_TRIGGER_FALLING, "vir-v4l2-irq", s);
    if (ret < 0) {
        dev_err(&pdev->dev, "failed to request rx irq: %d\n", ret);
        return ret;
    }

    // 关闭中断
    disable_irq_nosync(s->irq);
    
    return 0;

err_free_controls:
	v4l2_device_unregister(&s->v4l2_dev);
    
err_free_mem:
    kfree(s);
    return ret;
}

static int vir_v4l2_dev_remove(struct platform_device *pdev)
{
    struct vir_v4l2_device *s = platform_get_drvdata(pdev);

    mutex_lock(&s->vb_queue_lock);
    mutex_lock(&s->v4l2_lock);
    /* No need to keep the urbs around after disconnection */
    s->udev = NULL;
    v4l2_device_disconnect(&s->v4l2_dev);
    video_unregister_device(&s->vdev);
    mutex_unlock(&s->v4l2_lock);
    mutex_unlock(&s->vb_queue_lock);

    v4l2_device_put(&s->v4l2_dev);

    return 0;
}

static const struct of_device_id vir_v4l2_dev_id[] = {
    { .compatible = "jz2440,virtual_v4l2_dev", },
    {},
};
MODULE_DEVICE_TABLE(of, vir_v4l2_dev_id);

static struct platform_driver vir_v4l2_dev_driver = {
    .probe = vir_v4l2_dev_probe,
    .remove = vir_v4l2_dev_remove,
    .driver = {
        .name = "jz2440-vir-v4l2-dev",
        .of_match_table = of_match_ptr(vir_v4l2_dev_id),
    }
};


/*
 * init入口函数
*/
static int vir_v4l2_drv_init(void)
{
    int ret = platform_driver_register(&vir_v4l2_dev_driver);
    if (ret < 0) {
        dev_err(NULL, "spi_vir_master_init failed\n");
        return -EBUSY;
    }
    
    return ret;
}

/*
 * exit出口函数
 */
static void vir_v4l2_drv_exit(void)
{
    platform_driver_unregister(&vir_v4l2_dev_driver);
    return;
}

module_init(vir_v4l2_drv_init);
module_exit(vir_v4l2_drv_exit);


MODULE_AUTHOR("huang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("virtual v4l2 driver");


